1 /*!
2  * jQuery Validation Plugin v1.
17.0
3  *
4  * https://jqueryvalidation.org/
5  *
6  * Copyright (c)
2017 Jörn Zaefferer
7  * Released under the MIT license
8  */

9 (function( factory ) {
10     
if ( typeof define === "function" && define.amd ) {
11         define( [
"jquery"], factory );
12     }
else if (typeof module === "object" && module.exports) {
13         module.exports = factory( require(
"jquery" ) );
14     }
else {
15         factory( jQuery );
16     }
17 }(function( $ ) {
18
19 $.extend( $.fn, {
20
21     
// https://jqueryvalidation.org/validate/
22     validate: function( options ) {
23
24         
// If nothing is selected, return nothing; can't chain anyway
25         
if ( !this.length ) {
26             
if ( options && options.debug && window.console ) {
27                 console.warn(
"Nothing selected, can't validate, returning nothing." );
28             }
29             
return;
30         }
31
32         
// Check if a validator for this form was already created
33         
var validator = $.data( this[ 0 ], "validator" );
34         
if ( validator ) {
35             
return validator;
36         }
37
38         
// Add novalidate tag if HTML5.
39         
this.attr( "novalidate", "novalidate" );
40
41         validator =
new $.validator( options, this[ 0 ] );
42         $.data(
this[ 0 ], "validator", validator );
43
44         
if ( validator.settings.onsubmit ) {
45
46             
this.on( "click.validate", ":submit", function( event ) {
47
48                 
// Track the used submit button to properly handle scripted
49                 
// submits later.
50                 validator.submitButton =
event.currentTarget;
51
52                 
// Allow suppressing validation by adding a cancel class to the submit button
53                 
if ( $( this ).hasClass( "cancel" ) ) {
54                     validator.cancelSubmit =
true;
55                 }
56
57                 
// Allow suppressing validation by adding the html5 formnovalidate attribute to the submit button
58                 
if ( $( this ).attr( "formnovalidate" ) !== undefined ) {
59                     validator.cancelSubmit =
true;
60                 }
61             } );
62
63             
// Validate the form on submit
64             
this.on( "submit.validate", function( event ) {
65                 
if ( validator.settings.debug ) {
66
67                     
// Prevent form submit to be able to see console output
68                     
event.preventDefault();
69                 }
70                 function handle() {
71                     
var hidden, result;
72
73                     
// Insert a hidden input as a replacement for the missing submit button
74                     
// The hidden input is inserted in two cases:
75                     
// - A user defined a `submitHandler`
76                     
// - There was a pending request due to `remote` method and `stopRequest()`
77                     
// was called to submit the form in case it's valid
78                     
if ( validator.submitButton && ( validator.settings.submitHandler || validator.formSubmitted ) ) {
79                         hidden = $(
"<input type='hidden'/>" )
80                             .attr(
"name", validator.submitButton.name )
81                             .val( $( validator.submitButton ).val() )
82                             .appendTo( validator.currentForm );
83                     }
84
85                     
if ( validator.settings.submitHandler ) {
86                         result = validator.settings.submitHandler.call( validator, validator.currentForm,
event );
87                         
if ( hidden ) {
88
89                             
// And clean up afterwards; thanks to no-block-scope, hidden can be referenced
90                             hidden.
remove();
91                         }
92                         
if ( result !== undefined ) {
93                             
return result;
94                         }
95                         
return false;
96                     }
97                     
return true;
98                 }
99
100                 
// Prevent submit for invalid forms or custom submit handlers
101                 
if ( validator.cancelSubmit ) {
102                     validator.cancelSubmit =
false;
103                     
return handle();
104                 }
105                 
if ( validator.form() ) {
106                     
if ( validator.pendingRequest ) {
107                         validator.formSubmitted =
true;
108                         
return false;
109                     }
110                     
return handle();
111                 }
else {
112                     validator.focusInvalid();
113                     
return false;
114                 }
115             } );
116         }
117
118         
return validator;
119     },
120
121     
// https://jqueryvalidation.org/valid/
122     valid: function() {
123         
var valid, validator, errorList;
124
125         
if ( $( this[ 0 ] ).is( "form" ) ) {
126             valid =
this.validate().form();
127         }
else {
128             errorList = [];
129             valid =
true;
130             validator = $(
this[ 0 ].form ).validate();
131             
this.each( function() {
132                 valid = validator.element(
this ) && valid;
133                 
if ( !valid ) {
134                     errorList = errorList.concat( validator.errorList );
135                 }
136             } );
137             validator.errorList = errorList;
138         }
139         
return valid;
140     },
141
142     
// https://jqueryvalidation.org/rules/
143     rules: function( command, argument ) {
144         
var element = this[ 0 ],
145             settings, staticRules, existingRules, data, param, filtered;
146
147         
// If nothing is selected, return empty object; can't chain anyway
148         
if ( element == null ) {
149             
return;
150         }
151
152         
if ( !element.form && element.hasAttribute( "contenteditable" ) ) {
153             element.form =
this.closest( "form" )[ 0 ];
154             element.name =
this.attr( "name" );
155         }
156
157         
if ( element.form == null ) {
158             
return;
159         }
160
161         
if ( command ) {
162             settings = $.data( element.form,
"validator" ).settings;
163             staticRules = settings.rules;
164             existingRules = $.validator.staticRules( element );
165             
switch ( command ) {
166             
case "add":
167                 $.extend( existingRules, $.validator.normalizeRule( argument ) );
168
169                 
// Remove messages from rules, but allow them to be set separately
170                 delete existingRules.messages;
171                 staticRules[ element.name ] = existingRules;
172                 
if ( argument.messages ) {
173                     settings.messages[ element.name ] = $.extend( settings.messages[ element.name ], argument.messages );
174                 }
175                 
break;
176             
case "remove":
177                 
if ( !argument ) {
178                     delete staticRules[ element.name ];
179                     
return existingRules;
180                 }
181                 filtered = {};
182                 $.each( argument.split( /\s/ ), function( index, method ) {
183                     filtered[ method ] = existingRules[ method ];
184                     delete existingRules[ method ];
185                 } );
186                 
return filtered;
187             }
188         }
189
190         data = $.validator.normalizeRules(
191         $.extend(
192             {},
193             $.validator.classRules( element ),
194             $.validator.attributeRules( element ),
195             $.validator.dataRules( element ),
196             $.validator.staticRules( element )
197         ), element );
198
199         
// Make sure required is at front
200         
if ( data.required ) {
201             param = data.required;
202             delete data.required;
203             data = $.extend( { required: param }, data );
204         }
205
206         
// Make sure remote is at back
207         
if ( data.remote ) {
208             param = data.remote;
209             delete data.remote;
210             data = $.extend( data, { remote: param } );
211         }
212
213         
return data;
214     }
215 } );

216
217 // Custom selectors

218 $.extend( $.expr.pseudos || $.expr[
":" ], { // '|| $.expr[ ":" ]' here enables backwards compatibility to jQuery 1.7. Can be removed when dropping jQ 1.7.x support
219
220     
// https://jqueryvalidation.org/blank-selector/
221     blank: function( a ) {
222         
return !$.trim( "" + $( a ).val() );
223     },
224
225     
// https://jqueryvalidation.org/filled-selector/
226     filled: function( a ) {
227         
var val = $( a ).val();
228         
return val !== null && !!$.trim( "" + val );
229     },
230
231     
// https://jqueryvalidation.org/unchecked-selector/
232     
unchecked: function( a ) {
233         
return !$( a ).prop( "checked" );
234     }
235 } );

236
237 // Constructor
for validator
238 $.validator = function( options, form ) {
239     
this.settings = $.extend( true, {}, $.validator.defaults, options );
240     
this.currentForm = form;
241     
this.init();
242 };

243
244 // https://jqueryvalidation.org/jQuery.validator.format/

245 $.validator.format = function( source,
params ) {
246     
if ( arguments.length === 1 ) {
247         
return function() {
248             
var args = $.makeArray( arguments );
249             args.unshift( source );
250             
return $.validator.format.apply( this, args );
251         };
252     }
253     
if ( params === undefined ) {
254         
return source;
255     }
256     
if ( arguments.length > 2 && params.constructor !== Array ) {
257         
params = $.makeArray( arguments ).slice( 1 );
258     }
259     
if ( params.constructor !== Array ) {
260         
params = [ params ];
261     }
262     $.each(
params, function( i, n ) {
263         source = source.replace(
new RegExp( "\\{" + i + "\\}", "g" ), function() {
264             
return n;
265         } );
266     } );
267     
return source;
268 };
269
270 $.extend( $.validator, {
271
272     defaults: {
273         messages: {},
274         groups: {},
275         rules: {},
276         errorClass:
"error",
277         pendingClass:
"pending",
278         validClass:
"valid",
279         errorElement:
"label",
280         focusCleanup:
false,
281         focusInvalid:
true,
282         errorContainer: $( [] ),
283         errorLabelContainer: $( [] ),
284         onsubmit:
true,
285         ignore:
":hidden",
286         ignoreTitle:
false,
287         onfocusin: function( element ) {
288             
this.lastActive = element;
289
290             
// Hide error label and remove error class on focus if enabled
291             
if ( this.settings.focusCleanup ) {
292                 
if ( this.settings.unhighlight ) {
293                     
this.settings.unhighlight.call( this, element, this.settings.errorClass, this.settings.validClass );
294                 }
295                 
this.hideThese( this.errorsFor( element ) );
296             }
297         },
298         onfocusout: function( element ) {
299             
if ( !this.checkable( element ) && ( element.name in this.submitted || !this.optional( element ) ) ) {
300                 
this.element( element );
301             }
302         },
303         onkeyup: function( element,
event ) {
304
305             
// Avoid revalidate the field when pressing one of the following keys
306             
// Shift => 16
307             
// Ctrl => 17
308             
// Alt => 18
309             
// Caps lock => 20
310             
// End => 35
311             
// Home => 36
312             
// Left arrow => 37
313             
// Up arrow => 38
314             
// Right arrow => 39
315             
// Down arrow => 40
316             
// Insert => 45
317             
// Num lock => 144
318             
// AltGr key => 225
319             
var excludedKeys = [
320                 
16, 17, 18, 20, 35, 36, 37,
321                 
38, 39, 40, 45, 144, 225
322             ];
323
324             
if ( event.which === 9 && this.elementValue( element ) === "" || $.inArray( event.keyCode, excludedKeys ) !== -1 ) {
325                 
return;
326             }
else if ( element.name in this.submitted || element.name in this.invalid ) {
327                 
this.element( element );
328             }
329         },
330         onclick: function( element ) {
331
332             
// Click on selects, radiobuttons and checkboxes
333             
if ( element.name in this.submitted ) {
334                 
this.element( element );
335
336             
// Or option elements, check parent select in that case
337             }
else if ( element.parentNode.name in this.submitted ) {
338                 
this.element( element.parentNode );
339             }
340         },
341         highlight: function( element, errorClass, validClass ) {
342             
if ( element.type === "radio" ) {
343                 
this.findByName( element.name ).addClass( errorClass ).removeClass( validClass );
344             }
else {
345                 $( element ).addClass( errorClass ).removeClass( validClass );
346             }
347         },
348         unhighlight: function( element, errorClass, validClass ) {
349             
if ( element.type === "radio" ) {
350                 
this.findByName( element.name ).removeClass( errorClass ).addClass( validClass );
351             }
else {
352                 $( element ).removeClass( errorClass ).addClass( validClass );
353             }
354         }
355     },
356
357     
// https://jqueryvalidation.org/jQuery.validator.setDefaults/
358     setDefaults: function( settings ) {
359         $.extend( $.validator.defaults, settings );
360     },
361
362     messages: {
363         required:
"This field is required.",
364         remote:
"Please fix this field.",
365         email:
"Please enter a valid email address.",
366         url:
"Please enter a valid URL.",
367         date:
"Please enter a valid date.",
368         dateISO:
"Please enter a valid date (ISO).",
369         number:
"Please enter a valid number.",
370         digits:
"Please enter only digits.",
371         equalTo:
"Please enter the same value again.",
372         maxlength: $.validator.format(
"Please enter no more than {0} characters." ),
373         minlength: $.validator.format(
"Please enter at least {0} characters." ),
374         rangelength: $.validator.format(
"Please enter a value between {0} and {1} characters long." ),
375         range: $.validator.format(
"Please enter a value between {0} and {1}." ),
376         max: $.validator.format(
"Please enter a value less than or equal to {0}." ),
377         min: $.validator.format(
"Please enter a value greater than or equal to {0}." ),
378         step: $.validator.format(
"Please enter a multiple of {0}." )
379     },
380
381     autoCreateRanges:
false,
382
383     prototype: {
384
385         init: function() {
386             
this.labelContainer = $( this.settings.errorLabelContainer );
387             
this.errorContext = this.labelContainer.length && this.labelContainer || $( this.currentForm );
388             
this.containers = $( this.settings.errorContainer ).add( this.settings.errorLabelContainer );
389             
this.submitted = {};
390             
this.valueCache = {};
391             
this.pendingRequest = 0;
392             
this.pending = {};
393             
this.invalid = {};
394             
this.reset();
395
396             
var groups = ( this.groups = {} ),
397                 rules;
398             $.each(
this.settings.groups, function( key, value ) {
399                 
if ( typeof value === "string" ) {
400                     
value = value.split( /\s/ );
401                 }
402                 $.each(
value, function( index, name ) {
403                     groups[ name ] = key;
404                 } );
405             } );
406             rules =
this.settings.rules;
407             $.each( rules, function( key,
value ) {
408                 rules[ key ] = $.validator.normalizeRule(
value );
409             } );
410
411             function
delegate( event ) {
412
413                 
// Set form expando on contenteditable
414                 
if ( !this.form && this.hasAttribute( "contenteditable" ) ) {
415                     
this.form = $( this ).closest( "form" )[ 0 ];
416                     
this.name = $( this ).attr( "name" );
417                 }
418
419                 
var validator = $.data( this.form, "validator" ),
420                     eventType =
"on" + event.type.replace( /^validate/, "" ),
421                     settings = validator.settings;
422                 
if ( settings[ eventType ] && !$( this ).is( settings.ignore ) ) {
423                     settings[ eventType ].call( validator,
this, event );
424                 }
425             }
426
427             $(
this.currentForm )
428                 .
on( "focusin.validate focusout.validate keyup.validate",
429                     
":text, [type='password'], [type='file'], select, textarea, [type='number'], [type='search'], " +
430                     
"[type='tel'], [type='url'], [type='email'], [type='datetime'], [type='date'], [type='month'], " +
431                     
"[type='week'], [type='time'], [type='datetime-local'], [type='range'], [type='color'], " +
432                     
"[type='radio'], [type='checkbox'], [contenteditable], [type='button']", delegate )
433
434                 
// Support: Chrome, oldIE
435                 
// "select" is provided as event.target when clicking a option
436                 .
on( "click.validate", "select, option, [type='radio'], [type='checkbox']", delegate );
437
438             
if ( this.settings.invalidHandler ) {
439                 $(
this.currentForm ).on( "invalid-form.validate", this.settings.invalidHandler );
440             }
441         },
442
443         
// https://jqueryvalidation.org/Validator.form/
444         form: function() {
445             
this.checkForm();
446             $.extend(
this.submitted, this.errorMap );
447             
this.invalid = $.extend( {}, this.errorMap );
448             
if ( !this.valid() ) {
449                 $(
this.currentForm ).triggerHandler( "invalid-form", [ this ] );
450             }
451             
this.showErrors();
452             
return this.valid();
453         },
454
455         checkForm: function() {
456             
this.prepareForm();
457             
for ( var i = 0, elements = ( this.currentElements = this.elements() ); elements[ i ]; i++ ) {
458                 
this.check( elements[ i ] );
459             }
460             
return this.valid();
461         },
462
463         
// https://jqueryvalidation.org/Validator.element/
464         element: function( element ) {
465             
var cleanElement = this.clean( element ),
466                 checkElement =
this.validationTargetFor( cleanElement ),
467                 v =
this,
468                 result =
true,
469                 rs,
group;
470
471             
if ( checkElement === undefined ) {
472                 delete
this.invalid[ cleanElement.name ];
473             }
else {
474                 
this.prepareElement( checkElement );
475                 
this.currentElements = $( checkElement );
476
477                 
// If this element is grouped, then validate all group elements already
478                 
// containing a value
479                 
group = this.groups[ checkElement.name ];
480                 
if ( group ) {
481                     $.each(
this.groups, function( name, testgroup ) {
482                         
if ( testgroup === group && name !== checkElement.name ) {
483                             cleanElement = v.validationTargetFor( v.clean( v.findByName( name ) ) );
484                             
if ( cleanElement && cleanElement.name in v.invalid ) {
485                                 v.currentElements.push( cleanElement );
486                                 result = v.check( cleanElement ) && result;
487                             }
488                         }
489                     } );
490                 }
491
492                 rs =
this.check( checkElement ) !== false;
493                 result = result && rs;
494                 
if ( rs ) {
495                     
this.invalid[ checkElement.name ] = false;
496                 }
else {
497                     
this.invalid[ checkElement.name ] = true;
498                 }
499
500                 
if ( !this.numberOfInvalids() ) {
501
502                     
// Hide error containers on last error
503                     
this.toHide = this.toHide.add( this.containers );
504                 }
505                 
this.showErrors();
506
507                 
// Add aria-invalid status for screen readers
508                 $( element ).attr(
"aria-invalid", !rs );
509             }
510
511             
return result;
512         },
513
514         
// https://jqueryvalidation.org/Validator.showErrors/
515         showErrors: function( errors ) {
516             
if ( errors ) {
517                 
var validator = this;
518
519                 
// Add items to error list and map
520                 $.extend(
this.errorMap, errors );
521                 
this.errorList = $.map( this.errorMap, function( message, name ) {
522                     
return {
523                         message: message,
524                         element: validator.findByName( name )[
0 ]
525                     };
526                 } );
527
528                 
// Remove items from success list
529                 
this.successList = $.grep( this.successList, function( element ) {
530                     
return !( element.name in errors );
531                 } );
532             }
533             
if ( this.settings.showErrors ) {
534                 
this.settings.showErrors.call( this, this.errorMap, this.errorList );
535             }
else {
536                 
this.defaultShowErrors();
537             }
538         },
539
540         
// https://jqueryvalidation.org/Validator.resetForm/
541         resetForm: function() {
542             
if ( $.fn.resetForm ) {
543                 $(
this.currentForm ).resetForm();
544             }
545             
this.invalid = {};
546             
this.submitted = {};
547             
this.prepareForm();
548             
this.hideErrors();
549             
var elements = this.elements()
550                 .removeData(
"previousValue" )
551                 .removeAttr(
"aria-invalid" );
552
553             
this.resetElements( elements );
554         },
555
556         resetElements: function( elements ) {
557             
var i;
558
559             
if ( this.settings.unhighlight ) {
560                 
for ( i = 0; elements[ i ]; i++ ) {
561                     
this.settings.unhighlight.call( this, elements[ i ],
562                         
this.settings.errorClass, "" );
563                     
this.findByName( elements[ i ].name ).removeClass( this.settings.validClass );
564                 }
565             }
else {
566                 elements
567                     .removeClass(
this.settings.errorClass )
568                     .removeClass(
this.settings.validClass );
569             }
570         },
571
572         numberOfInvalids: function() {
573             
return this.objectLength( this.invalid );
574         },
575
576         objectLength: function( obj ) {
577             
/* jshint unused: false */
578             
var count = 0,
579                 i;
580             
for ( i in obj ) {
581
582                 
// This check allows counting elements with empty error
583                 
// message as invalid elements
584                 
if ( obj[ i ] !== undefined && obj[ i ] !== null && obj[ i ] !== false ) {
585                     count++;
586                 }
587             }
588             
return count;
589         },
590
591         hideErrors: function() {
592             
this.hideThese( this.toHide );
593         },
594
595         hideThese: function( errors ) {
596             errors.not(
this.containers ).text( "" );
597             
this.addWrapper( errors ).hide();
598         },
599
600         valid: function() {
601             
return this.size() === 0;
602         },
603
604         size: function() {
605             
return this.errorList.length;
606         },
607
608         focusInvalid: function() {
609             
if ( this.settings.focusInvalid ) {
610                 
try {
611                     $(
this.findLastActive() || this.errorList.length && this.errorList[ 0 ].element || [] )
612                     .filter(
":visible" )
613                     .focus()
614
615                     
// Manually trigger focusin event; without it, focusin handler isn't called, findLastActive won't have anything to find
616                     .trigger(
"focusin" );
617                 }
catch ( e ) {
618
619                     
// Ignore IE throwing errors when focusing hidden elements
620                 }
621             }
622         },
623
624         findLastActive: function() {
625             
var lastActive = this.lastActive;
626             
return lastActive && $.grep( this.errorList, function( n ) {
627                 
return n.element.name === lastActive.name;
628             } ).length ===
1 && lastActive;
629         },
630
631         elements: function() {
632             
var validator = this,
633                 rulesCache = {};
634
635             
// Select all valid inputs inside the form (no submit or reset buttons)
636             
return $( this.currentForm )
637             .find(
"input, select, textarea, [contenteditable]" )
638             .not(
":submit, :reset, :image, :disabled" )
639             .not(
this.settings.ignore )
640             .filter( function() {
641                 
var name = this.name || $( this ).attr( "name" ); // For contenteditable
642                 
if ( !name && validator.settings.debug && window.console ) {
643                     console.error(
"%o has no name assigned", this );
644                 }
645
646                 
// Set form expando on contenteditable
647                 
if ( this.hasAttribute( "contenteditable" ) ) {
648                     
this.form = $( this ).closest( "form" )[ 0 ];
649                     
this.name = name;
650                 }
651
652                 
// Select only the first element for each name, and only those with rules specified
653                 
if ( name in rulesCache || !validator.objectLength( $( this ).rules() ) ) {
654                     
return false;
655                 }
656
657                 rulesCache[ name ] =
true;
658                 
return true;
659             } );
660         },
661
662         clean: function( selector ) {
663             
return $( selector )[ 0 ];
664         },
665
666         errors: function() {
667             
var errorClass = this.settings.errorClass.split( " " ).join( "." );
668             
return $( this.settings.errorElement + "." + errorClass, this.errorContext );
669         },
670
671         resetInternals: function() {
672             
this.successList = [];
673             
this.errorList = [];
674             
this.errorMap = {};
675             
this.toShow = $( [] );
676             
this.toHide = $( [] );
677         },
678
679         reset: function() {
680             
this.resetInternals();
681             
this.currentElements = $( [] );
682         },
683
684         prepareForm: function() {
685             
this.reset();
686             
this.toHide = this.errors().add( this.containers );
687         },
688
689         prepareElement: function( element ) {
690             
this.reset();
691             
this.toHide = this.errorsFor( element );
692         },
693
694         elementValue: function( element ) {
695             
var $element = $( element ),
696                 type = element.type,
697                 val, idx;
698
699             
if ( type === "radio" || type === "checkbox" ) {
700                 
return this.findByName( element.name ).filter( ":checked" ).val();
701             }
else if ( type === "number" && typeof element.validity !== "undefined" ) {
702                 
return element.validity.badInput ? "NaN" : $element.val();
703             }
704
705             
if ( element.hasAttribute( "contenteditable" ) ) {
706                 val = $element.text();
707             }
else {
708                 val = $element.val();
709             }
710
711             
if ( type === "file" ) {
712
713                 
// Modern browser (chrome & safari)
714                 
if ( val.substr( 0, 12 ) === "C:\\fakepath\\" ) {
715                     
return val.substr( 12 );
716                 }
717
718                 
// Legacy browsers
719                 
// Unix-based path
720                 idx = val.lastIndexOf(
"/" );
721                 
if ( idx >= 0 ) {
722                     
return val.substr( idx + 1 );
723                 }
724
725                 
// Windows-based path
726                 idx = val.lastIndexOf(
"\\" );
727                 
if ( idx >= 0 ) {
728                     
return val.substr( idx + 1 );
729                 }
730
731                 
// Just the file name
732                 
return val;
733             }
734
735             
if ( typeof val === "string" ) {
736                 
return val.replace( /\r/g, "" );
737             }
738             
return val;
739         },
740
741         check: function( element ) {
742             element =
this.validationTargetFor( this.clean( element ) );
743
744             
var rules = $( element ).rules(),
745                 rulesCount = $.map( rules, function( n, i ) {
746                     
return i;
747                 } ).length,
748                 dependencyMismatch =
false,
749                 val =
this.elementValue( element ),
750                 result, method, rule, normalizer;
751
752             
// Prioritize the local normalizer defined for this element over the global one
753             
// if the former exists, otherwise user the global one in case it exists.
754             
if ( typeof rules.normalizer === "function" ) {
755                 normalizer = rules.normalizer;
756             }
else if ( typeof this.settings.normalizer === "function" ) {
757                 normalizer =
this.settings.normalizer;
758             }
759
760             
// If normalizer is defined, then call it to retreive the changed value instead
761             
// of using the real one.
762             
// Note that `this` in the normalizer is `element`.
763             
if ( normalizer ) {
764                 val = normalizer.call( element, val );
765
766                 
if ( typeof val !== "string" ) {
767                     
throw new TypeError( "The normalizer should return a string value." );
768                 }
769
770                 
// Delete the normalizer from rules to avoid treating it as a pre-defined method.
771                 delete rules.normalizer;
772             }
773
774             
for ( method in rules ) {
775                 rule = { method: method, parameters: rules[ method ] };
776                 
try {
777                     result = $.validator.methods[ method ].call(
this, val, element, rule.parameters );
778
779                     
// If a method indicates that the field is optional and therefore valid,
780                     
// don't mark it as valid when there are no other rules
781                     
if ( result === "dependency-mismatch" && rulesCount === 1 ) {
782                         dependencyMismatch =
true;
783                         
continue;
784                     }
785                     dependencyMismatch =
false;
786
787                     
if ( result === "pending" ) {
788                         
this.toHide = this.toHide.not( this.errorsFor( element ) );
789                         
return;
790                     }
791
792                     
if ( !result ) {
793                         
this.formatAndAdd( element, rule );
794                         
return false;
795                     }
796                 }
catch ( e ) {
797                     
if ( this.settings.debug && window.console ) {
798                         console.log(
"Exception occurred when checking element " + element.id + ", check the '" + rule.method + "' method.", e );
799                     }
800                     
if ( e instanceof TypeError ) {
801                         e.message +=
". Exception occurred when checking element " + element.id + ", check the '" + rule.method + "' method.";
802                     }
803
804                     
throw e;
805                 }
806             }
807             
if ( dependencyMismatch ) {
808                 
return;
809             }
810             
if ( this.objectLength( rules ) ) {
811                 
this.successList.push( element );
812             }
813             
return true;
814         },
815
816         
// Return the custom message for the given element and validation method
817         
// specified in the element's HTML5 data attribute
818         
// return the generic message if present and no method specific message is present
819         customDataMessage: function( element, method ) {
820             
return $( element ).data( "msg" + method.charAt( 0 ).toUpperCase() +
821                 method.substring(
1 ).toLowerCase() ) || $( element ).data( "msg" );
822         },
823
824         
// Return the custom message for the given element name and validation method
825         customMessage: function( name, method ) {
826             
var m = this.settings.messages[ name ];
827             
return m && ( m.constructor === String ? m : m[ method ] );
828         },
829
830         
// Return the first defined argument, allowing empty strings
831         findDefined: function() {
832             
for ( var i = 0; i < arguments.length; i++ ) {
833                 
if ( arguments[ i ] !== undefined ) {
834                     
return arguments[ i ];
835                 }
836             }
837             
return undefined;
838         },
839
840         
// The second parameter 'rule' used to be a string, and extended to an object literal
841         
// of the following form:
842         
// rule = {
843         
// method: "method name",
844         
// parameters: "the given method parameters"
845         
// }
846         
//
847         
// The old behavior still supported, kept to maintain backward compatibility with
848         
// old code, and will be removed in the next major release.
849         defaultMessage: function( element, rule ) {
850             
if ( typeof rule === "string" ) {
851                 rule = { method: rule };
852             }
853
854             
var message = this.findDefined(
855                     
this.customMessage( element.name, rule.method ),
856                     
this.customDataMessage( element, rule.method ),
857
858                     
// 'title' is never undefined, so handle empty string as undefined
859                     !
this.settings.ignoreTitle && element.title || undefined,
860                     $.validator.messages[ rule.method ],
861                     
"<strong>Warning: No message defined for " + element.name + "</strong>"
862                 ),
863                 theregex = /\$?\{(\d+)\}/g;
864             
if ( typeof message === "function" ) {
865                 message = message.call(
this, rule.parameters, element );
866             }
else if ( theregex.test( message ) ) {
867                 message = $.validator.format( message.replace( theregex,
"{$1}" ), rule.parameters );
868             }
869
870             
return message;
871         },
872
873         formatAndAdd: function( element, rule ) {
874             
var message = this.defaultMessage( element, rule );
875
876             
this.errorList.push( {
877                 message: message,
878                 element: element,
879                 method: rule.method
880             } );
881
882             
this.errorMap[ element.name ] = message;
883             
this.submitted[ element.name ] = message;
884         },
885
886         addWrapper: function( toToggle ) {
887             
if ( this.settings.wrapper ) {
888                 toToggle = toToggle.
add( toToggle.parent( this.settings.wrapper ) );
889             }
890             
return toToggle;
891         },
892
893         defaultShowErrors: function() {
894             
var i, elements, error;
895             
for ( i = 0; this.errorList[ i ]; i++ ) {
896                 error =
this.errorList[ i ];
897                 
if ( this.settings.highlight ) {
898                     
this.settings.highlight.call( this, error.element, this.settings.errorClass, this.settings.validClass );
899                 }
900                 
this.showLabel( error.element, error.message );
901             }
902             
if ( this.errorList.length ) {
903                 
this.toShow = this.toShow.add( this.containers );
904             }
905             
if ( this.settings.success ) {
906                 
for ( i = 0; this.successList[ i ]; i++ ) {
907                     
this.showLabel( this.successList[ i ] );
908                 }
909             }
910             
if ( this.settings.unhighlight ) {
911                 
for ( i = 0, elements = this.validElements(); elements[ i ]; i++ ) {
912                     
this.settings.unhighlight.call( this, elements[ i ], this.settings.errorClass, this.settings.validClass );
913                 }
914             }
915             
this.toHide = this.toHide.not( this.toShow );
916             
this.hideErrors();
917             
this.addWrapper( this.toShow ).show();
918         },
919
920         validElements: function() {
921             
return this.currentElements.not( this.invalidElements() );
922         },
923
924         invalidElements: function() {
925             
return $( this.errorList ).map( function() {
926                 
return this.element;
927             } );
928         },
929
930         showLabel: function( element, message ) {
931             
var place, group, errorID, v,
932                 error =
this.errorsFor( element ),
933                 elementID =
this.idOrName( element ),
934                 describedBy = $( element ).attr(
"aria-describedby" );
935
936             
if ( error.length ) {
937
938                 
// Refresh error/success class
939                 
error.removeClass( this.settings.validClass ).addClass( this.settings.errorClass );
940
941                 
// Replace message on existing label
942                 error.html( message );
943             }
else {
944
945                 
// Create error element
946                 error = $(
"<" + this.settings.errorElement + ">" )
947                     .attr(
"id", elementID + "-error" )
948                     .addClass(
this.settings.errorClass )
949                     .html( message ||
"" );
950
951                 
// Maintain reference to the element to be placed into the DOM
952                 place = error;
953                 
if ( this.settings.wrapper ) {
954
955                     
// Make sure the element is visible, even in IE
956                     
// actually showing the wrapped element is handled elsewhere
957                     place = error.hide().show().wrap(
"<" + this.settings.wrapper + "/>" ).parent();
958                 }
959                 
if ( this.labelContainer.length ) {
960                     
this.labelContainer.append( place );
961                 }
else if ( this.settings.errorPlacement ) {
962                     
this.settings.errorPlacement.call( this, place, $( element ) );
963                 }
else {
964                     place.insertAfter( element );
965                 }
966
967                 
// Link error back to the element
968                 
if ( error.is( "label" ) ) {
969
970                     
// If the error is a label, then associate using 'for'
971                     error.attr(
"for", elementID );
972
973                     
// If the element is not a child of an associated label, then it's necessary
974                     
// to explicitly apply aria-describedby
975                 }
else if ( error.parents( "label[for='" + this.escapeCssMeta( elementID ) + "']" ).length === 0 ) {
976                     errorID = error.attr(
"id" );
977
978                     
// Respect existing non-error aria-describedby
979                     
if ( !describedBy ) {
980                         describedBy = errorID;
981                     }
else if ( !describedBy.match( new RegExp( "\\b" + this.escapeCssMeta( errorID ) + "\\b" ) ) ) {
982
983                         
// Add to end of list if not already present
984                         describedBy +=
" " + errorID;
985                     }
986                     $( element ).attr(
"aria-describedby", describedBy );
987
988                     
// If this element is grouped, then assign to all elements in the same group
989                     
group = this.groups[ element.name ];
990                     
if ( group ) {
991                         v =
this;
992                         $.each( v.groups, function( name, testgroup ) {
993                             
if ( testgroup === group ) {
994                                 $(
"[name='" + v.escapeCssMeta( name ) + "']", v.currentForm )
995                                     .attr(
"aria-describedby", error.attr( "id" ) );
996                             }
997                         } );
998                     }
999                 }
1000             }
1001             
if ( !message && this.settings.success ) {
1002                 error.text(
"" );
1003                 
if ( typeof this.settings.success === "string" ) {
1004                     error.addClass(
this.settings.success );
1005                 }
else {
1006                     
this.settings.success( error, element );
1007                 }
1008             }
1009             
this.toShow = this.toShow.add( error );
1010         },
1011
1012         errorsFor: function( element ) {
1013             
var name = this.escapeCssMeta( this.idOrName( element ) ),
1014                 describer = $( element ).attr(
"aria-describedby" ),
1015                 selector =
"label[for='" + name + "'], label[for='" + name + "'] *";
1016
1017             
// 'aria-describedby' should directly reference the error element
1018             
if ( describer ) {
1019                 selector = selector +
", #" + this.escapeCssMeta( describer )
1020                     .replace( /\s+/g,
", #" );
1021             }
1022
1023             
return this
1024                 .errors()
1025                 .filter( selector );
1026         },
1027
1028         
// See https://api.jquery.com/category/selectors/, for CSS
1029         
// meta-characters that should be escaped in order to be used with JQuery
1030         
// as a literal part of a name/id or any selector.
1031         escapeCssMeta: function(
string ) {
1032             
return string.replace( /([\\!"#$%&'()*+,./:;<=>?@\[\]^`{|}~])/g, "\\$1" );
1033         },
1034
1035         idOrName: function( element ) {
1036             
return this.groups[ element.name ] || ( this.checkable( element ) ? element.name : element.id || element.name );
1037         },
1038
1039         validationTargetFor: function( element ) {
1040
1041             
// If radio/checkbox, validate first element in group instead
1042             
if ( this.checkable( element ) ) {
1043                 element =
this.findByName( element.name );
1044             }
1045
1046             
// Always apply ignore filter
1047             
return $( element ).not( this.settings.ignore )[ 0 ];
1048         },
1049
1050         checkable: function( element ) {
1051             
return ( /radio|checkbox/i ).test( element.type );
1052         },
1053
1054         findByName: function( name ) {
1055             
return $( this.currentForm ).find( "[name='" + this.escapeCssMeta( name ) + "']" );
1056         },
1057
1058         getLength: function(
value, element ) {
1059             
switch ( element.nodeName.toLowerCase() ) {
1060             
case "select":
1061                 
return $( "option:selected", element ).length;
1062             
case "input":
1063                 
if ( this.checkable( element ) ) {
1064                     
return this.findByName( element.name ).filter( ":checked" ).length;
1065                 }
1066             }
1067             
return value.length;
1068         },
1069
1070         depend: function( param, element ) {
1071             
return this.dependTypes[ typeof param ] ? this.dependTypes[ typeof param ]( param, element ) : true;
1072         },
1073
1074         dependTypes: {
1075             "
boolean": function( param ) {
1076                 
return param;
1077             },
1078             "
string": function( param, element ) {
1079                 
return !!$( param, element.form ).length;
1080             },
1081             "
function": function( param, element ) {
1082                 
return param( element );
1083             }
1084         },
1085
1086         optional: function( element ) {
1087             
var val = this.elementValue( element );
1088             
return !$.validator.methods.required.call( this, val, element ) && "dependency-mismatch";
1089         },
1090
1091         startRequest: function( element ) {
1092             
if ( !this.pending[ element.name ] ) {
1093                 
this.pendingRequest++;
1094                 $( element ).addClass(
this.settings.pendingClass );
1095                 
this.pending[ element.name ] = true;
1096             }
1097         },
1098
1099         stopRequest: function( element, valid ) {
1100             
this.pendingRequest--;
1101
1102             
// Sometimes synchronization fails, make sure pendingRequest is never < 0
1103             
if ( this.pendingRequest < 0 ) {
1104                 
this.pendingRequest = 0;
1105             }
1106             delete
this.pending[ element.name ];
1107             $( element ).removeClass(
this.settings.pendingClass );
1108             
if ( valid && this.pendingRequest === 0 && this.formSubmitted && this.form() ) {
1109                 $(
this.currentForm ).submit();
1110
1111                 
// Remove the hidden input that was used as a replacement for the
1112                 
// missing submit button. The hidden input is added by `handle()`
1113                 
// to ensure that the value of the used submit button is passed on
1114                 
// for scripted submits triggered by this method
1115                 
if ( this.submitButton ) {
1116                     $( "
input:hidden[name='" + this.submitButton.name + "']", this.currentForm ).remove();
1117                 }
1118
1119                 
this.formSubmitted = false;
1120             }
else if ( !valid && this.pendingRequest === 0 && this.formSubmitted ) {
1121                 $(
this.currentForm ).triggerHandler( "invalid-form", [ this ] );
1122                 
this.formSubmitted = false;
1123             }
1124         },
1125
1126         previousValue: function( element, method ) {
1127             method =
typeof method === "string" && method || "remote";
1128
1129             
return $.data( element, "previousValue" ) || $.data( element, "previousValue", {
1130                 old:
null,
1131                 valid:
true,
1132                 message:
this.defaultMessage( element, { method: method } )
1133             } );
1134         },
1135
1136         
// Cleans up all forms and elements, removes validator-specific events
1137         destroy: function() {
1138             
this.resetForm();
1139
1140             $(
this.currentForm )
1141                 .off( "
.validate" )
1142                 .removeData( "
validator" )
1143                 .find( "
.validate-equalTo-blur" )
1144                     .off( "
.validate-equalTo" )
1145                     .removeClass( "
validate-equalTo-blur" );
1146         }
1147
1148     },
1149
1150     classRuleSettings: {
1151         required: { required:
true },
1152         email: { email:
true },
1153         url: { url:
true },
1154         date: { date:
true },
1155         dateISO: { dateISO:
true },
1156         number: { number:
true },
1157         digits: { digits:
true },
1158         creditcard: { creditcard:
true }
1159     },
1160
1161     addClassRules: function( className, rules ) {
1162         
if ( className.constructor === String ) {
1163             
this.classRuleSettings[ className ] = rules;
1164         }
else {
1165             $.extend(
this.classRuleSettings, className );
1166         }
1167     },
1168
1169     classRules: function( element ) {
1170         
var rules = {},
1171             classes = $( element ).attr( "
class" );
1172
1173         
if ( classes ) {
1174             $.each( classes.split( "
" ), function() {
1175                 
if ( this in $.validator.classRuleSettings ) {
1176                     $.extend( rules, $.validator.classRuleSettings[
this ] );
1177                 }
1178             } );
1179         }
1180         
return rules;
1181     },
1182
1183     normalizeAttributeRule: function( rules, type, method,
value ) {
1184
1185         
// Convert the value to a number for number inputs, and for text for backwards compability
1186         
// allows type="date" and others to be compared as strings
1187         
if ( /min|max|step/.test( method ) && ( type === null || /number|range|text/.test( type ) ) ) {
1188             
value = Number( value );
1189
1190             
// Support Opera Mini, which returns NaN for undefined minlength
1191             
if ( isNaN( value ) ) {
1192                 
value = undefined;
1193             }
1194         }
1195
1196         
if ( value || value === 0 ) {
1197             rules[ method ] =
value;
1198         }
else if ( type === method && type !== "range" ) {
1199
1200             
// Exception: the jquery validate 'range' method
1201             
// does not test for the html5 'range' type
1202             rules[ method ] =
true;
1203         }
1204     },
1205
1206     attributeRules: function( element ) {
1207         
var rules = {},
1208             $element = $( element ),
1209             type = element.getAttribute( "
type" ),
1210             method,
value;
1211
1212         
for ( method in $.validator.methods ) {
1213
1214             
// Support for <input required> in both html5 and older browsers
1215             
if ( method === "required" ) {
1216                 
value = element.getAttribute( method );
1217
1218                 
// Some browsers return an empty string for the required attribute
1219                 
// and non-HTML5 browsers might have required="" markup
1220                 
if ( value === "" ) {
1221                     
value = true;
1222                 }
1223
1224                 
// Force non-HTML5 browsers to return bool
1225                 
value = !!value;
1226             }
else {
1227                 
value = $element.attr( method );
1228             }
1229
1230             
this.normalizeAttributeRule( rules, type, method, value );
1231         }
1232
1233         
// 'maxlength' may be returned as -1, 2147483647 ( IE ) and 524288 ( safari ) for text inputs
1234         
if ( rules.maxlength && /-1|2147483647|524288/.test( rules.maxlength ) ) {
1235             delete rules.maxlength;
1236         }
1237
1238         
return rules;
1239     },
1240
1241     dataRules: function( element ) {
1242         
var rules = {},
1243             $element = $( element ),
1244             type = element.getAttribute( "
type" ),
1245             method,
value;
1246
1247         
for ( method in $.validator.methods ) {
1248             
value = $element.data( "rule" + method.charAt( 0 ).toUpperCase() + method.substring( 1 ).toLowerCase() );
1249             
this.normalizeAttributeRule( rules, type, method, value );
1250         }
1251         
return rules;
1252     },
1253
1254     staticRules: function( element ) {
1255         
var rules = {},
1256             validator = $.data( element.form, "
validator" );
1257
1258         
if ( validator.settings.rules ) {
1259             rules = $.validator.normalizeRule( validator.settings.rules[ element.name ] ) || {};
1260         }
1261         
return rules;
1262     },
1263
1264     normalizeRules: function( rules, element ) {
1265
1266         
// Handle dependency check
1267         $.each( rules, function( prop, val ) {
1268
1269             
// Ignore rule when param is explicitly false, eg. required:false
1270             
if ( val === false ) {
1271                 delete rules[ prop ];
1272                 
return;
1273             }
1274             
if ( val.param || val.depends ) {
1275                 
var keepRule = true;
1276                 
switch ( typeof val.depends ) {
1277                 
case "string":
1278                     keepRule = !!$( val.depends, element.form ).length;
1279                     
break;
1280                 
case "function":
1281                     keepRule = val.depends.call( element, element );
1282                     
break;
1283                 }
1284                 
if ( keepRule ) {
1285                     rules[ prop ] = val.param !== undefined ? val.param :
true;
1286                 }
else {
1287                     $.data( element.form, "
validator" ).resetElements( $( element ) );
1288                     delete rules[ prop ];
1289                 }
1290             }
1291         } );
1292
1293         
// Evaluate parameters
1294         $.each( rules, function( rule, parameter ) {
1295             rules[ rule ] = $.isFunction( parameter ) && rule !== "
normalizer" ? parameter( element ) : parameter;
1296         } );
1297
1298         
// Clean number parameters
1299         $.each( [ "
minlength", "maxlength" ], function() {
1300             
if ( rules[ this ] ) {
1301                 rules[
this ] = Number( rules[ this ] );
1302             }
1303         } );
1304         $.each( [ "
rangelength", "range" ], function() {
1305             
var parts;
1306             
if ( rules[ this ] ) {
1307                 
if ( $.isArray( rules[ this ] ) ) {
1308                     rules[
this ] = [ Number( rules[ this ][ 0 ] ), Number( rules[ this ][ 1 ] ) ];
1309                 }
else if ( typeof rules[ this ] === "string" ) {
1310                     parts = rules[
this ].replace( /[\[\]]/g, "" ).split( /[\s,]+/ );
1311                     rules[
this ] = [ Number( parts[ 0 ] ), Number( parts[ 1 ] ) ];
1312                 }
1313             }
1314         } );
1315
1316         
if ( $.validator.autoCreateRanges ) {
1317
1318             
// Auto-create ranges
1319             
if ( rules.min != null && rules.max != null ) {
1320                 rules.range = [ rules.min, rules.max ];
1321                 delete rules.min;
1322                 delete rules.max;
1323             }
1324             
if ( rules.minlength != null && rules.maxlength != null ) {
1325                 rules.rangelength = [ rules.minlength, rules.maxlength ];
1326                 delete rules.minlength;
1327                 delete rules.maxlength;
1328             }
1329         }
1330
1331         
return rules;
1332     },
1333
1334     
// Converts a simple string to a {string: true} rule, e.g., "required" to {required:true}
1335     normalizeRule: function( data ) {
1336         
if ( typeof data === "string" ) {
1337             
var transformed = {};
1338             $.each( data.split( /\s/ ), function() {
1339                 transformed[
this ] = true;
1340             } );
1341             data = transformed;
1342         }
1343         
return data;
1344     },
1345
1346     
// https://jqueryvalidation.org/jQuery.validator.addMethod/
1347     addMethod: function( name, method, message ) {
1348         $.validator.methods[ name ] = method;
1349         $.validator.messages[ name ] = message !== undefined ? message : $.validator.messages[ name ];
1350         
if ( method.length < 3 ) {
1351             $.validator.addClassRules( name, $.validator.normalizeRule( name ) );
1352         }
1353     },
1354
1355     
// https://jqueryvalidation.org/jQuery.validator.methods/
1356     methods: {
1357
1358         
// https://jqueryvalidation.org/required-method/
1359         required: function(
value, element, param ) {
1360
1361             
// Check if dependency is met
1362             
if ( !this.depend( param, element ) ) {
1363                 
return "dependency-mismatch";
1364             }
1365             
if ( element.nodeName.toLowerCase() === "select" ) {
1366
1367                 
// Could be an array for select-multiple or a string, both are fine this way
1368                 
var val = $( element ).val();
1369                 
return val && val.length > 0;
1370             }
1371             
if ( this.checkable( element ) ) {
1372                 
return this.getLength( value, element ) > 0;
1373             }
1374             
return value.length > 0;
1375         },
1376
1377         
// https://jqueryvalidation.org/email-method/
1378         email: function(
value, element ) {
1379
1380             
// From https://html.spec.whatwg.org/multipage/forms.html#valid-e-mail-address
1381             
// Retrieved 2014-01-14
1382             
// If you have a problem with this implementation, report a bug against the above spec
1383             
// Or use custom methods to implement your own email validation
1384             
return this.optional( element ) || /^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/.test( value );
1385         },
1386
1387         
// https://jqueryvalidation.org/url-method/
1388         url: function(
value, element ) {
1389
1390             
// Copyright (c) 2010-2013 Diego Perini, MIT licensed
1391             
// https://gist.github.com/dperini/729294
1392             
// see also https://mathiasbynens.be/demo/url-regex
1393             
// modified to allow protocol-relative URLs
1394             
return this.optional( element ) || /^(?:(?:(?:https?|ftp):)?\/\/)(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})).?)(?::\d{2,5})?(?:[/?#]\S*)?$/i.test( value );
1395         },
1396
1397         
// https://jqueryvalidation.org/date-method/
1398         date: function(
value, element ) {
1399             
return this.optional( element ) || !/Invalid|NaN/.test( new Date( value ).toString() );
1400         },
1401
1402         
// https://jqueryvalidation.org/dateISO-method/
1403         dateISO: function(
value, element ) {
1404             
return this.optional( element ) || /^\d{4}[\/\-](0?[1-9]|1[012])[\/\-](0?[1-9]|[12][0-9]|3[01])$/.test( value );
1405         },
1406
1407         
// https://jqueryvalidation.org/number-method/
1408         number: function(
value, element ) {
1409             
return this.optional( element ) || /^(?:-?\d+|-?\d{1,3}(?:,\d{3})+)?(?:\.\d+)?$/.test( value );
1410         },
1411
1412         
// https://jqueryvalidation.org/digits-method/
1413         digits: function(
value, element ) {
1414             
return this.optional( element ) || /^\d+$/.test( value );
1415         },
1416
1417         
// https://jqueryvalidation.org/minlength-method/
1418         minlength: function(
value, element, param ) {
1419             
var length = $.isArray( value ) ? value.length : this.getLength( value, element );
1420             
return this.optional( element ) || length >= param;
1421         },
1422
1423         
// https://jqueryvalidation.org/maxlength-method/
1424         maxlength: function(
value, element, param ) {
1425             
var length = $.isArray( value ) ? value.length : this.getLength( value, element );
1426             
return this.optional( element ) || length <= param;
1427         },
1428
1429         
// https://jqueryvalidation.org/rangelength-method/
1430         rangelength: function(
value, element, param ) {
1431             
var length = $.isArray( value ) ? value.length : this.getLength( value, element );
1432             
return this.optional( element ) || ( length >= param[ 0 ] && length <= param[ 1 ] );
1433         },
1434
1435         
// https://jqueryvalidation.org/min-method/
1436         min: function(
value, element, param ) {
1437             
return this.optional( element ) || value >= param;
1438         },
1439
1440         
// https://jqueryvalidation.org/max-method/
1441         max: function(
value, element, param ) {
1442             
return this.optional( element ) || value <= param;
1443         },
1444
1445         
// https://jqueryvalidation.org/range-method/
1446         range: function(
value, element, param ) {
1447             
return this.optional( element ) || ( value >= param[ 0 ] && value <= param[ 1 ] );
1448         },
1449
1450         
// https://jqueryvalidation.org/step-method/
1451         step: function(
value, element, param ) {
1452             
var type = $( element ).attr( "type" ),
1453                 errorMessage = "
Step attribute on input type " + type + " is not supported.",
1454                 supportedTypes = [ "
text", "number", "range" ],
1455                 re =
new RegExp( "\\b" + type + "\\b" ),
1456                 notSupported = type && !re.test( supportedTypes.
join() ),
1457                 decimalPlaces = function( num ) {
1458                     
var match = ( "" + num ).match( /(?:\.(\d+))?$/ );
1459                     
if ( !match ) {
1460                         
return 0;
1461                     }
1462
1463                     
// Number of digits right of decimal point.
1464                     
return match[ 1 ] ? match[ 1 ].length : 0;
1465                 },
1466                 toInt = function( num ) {
1467                     
return Math.round( num * Math.pow( 10, decimals ) );
1468                 },
1469                 valid =
true,
1470                 decimals;
1471
1472             
// Works only for text, number and range input types
1473             
// TODO find a way to support input types date, datetime, datetime-local, month, time and week
1474             
if ( notSupported ) {
1475                 
throw new Error( errorMessage );
1476             }
1477
1478             decimals = decimalPlaces( param );
1479
1480             
// Value can't have too many decimals
1481             
if ( decimalPlaces( value ) > decimals || toInt( value ) % toInt( param ) !== 0 ) {
1482                 valid =
false;
1483             }
1484
1485             
return this.optional( element ) || valid;
1486         },
1487
1488         
// https://jqueryvalidation.org/equalTo-method/
1489         equalTo: function(
value, element, param ) {
1490
1491             
// Bind to the blur event of the target in order to revalidate whenever the target field is updated
1492             
var target = $( param );
1493             
if ( this.settings.onfocusout && target.not( ".validate-equalTo-blur" ).length ) {
1494                 target.addClass( "
validate-equalTo-blur" ).on( "blur.validate-equalTo", function() {
1495                     $( element ).valid();
1496                 } );
1497             }
1498             
return value === target.val();
1499         },
1500
1501         
// https://jqueryvalidation.org/remote-method/
1502         remote: function(
value, element, param, method ) {
1503             
if ( this.optional( element ) ) {
1504                 
return "dependency-mismatch";
1505             }
1506
1507             method =
typeof method === "string" && method || "remote";
1508
1509             
var previous = this.previousValue( element, method ),
1510                 validator, data, optionDataString;
1511
1512             
if ( !this.settings.messages[ element.name ] ) {
1513                 
this.settings.messages[ element.name ] = {};
1514             }
1515             previous.originalMessage = previous.originalMessage ||
this.settings.messages[ element.name ][ method ];
1516             
this.settings.messages[ element.name ][ method ] = previous.message;
1517
1518             param =
typeof param === "string" && { url: param } || param;
1519             optionDataString = $.param( $.extend( { data:
value }, param.data ) );
1520             
if ( previous.old === optionDataString ) {
1521                 
return previous.valid;
1522             }
1523
1524             previous.old = optionDataString;
1525             validator =
this;
1526             
this.startRequest( element );
1527             data = {};
1528             data[ element.name ] =
value;
1529             $.ajax( $.extend(
true, {
1530                 mode: "
abort",
1531                 port: "
validate" + element.name,
1532                 dataType: "
json",
1533                 data: data,
1534                 context: validator.currentForm,
1535                 success: function( response ) {
1536                     
var valid = response === true || response === "true",
1537                         errors, message, submitted;
1538
1539                     validator.settings.messages[ element.name ][ method ] = previous.originalMessage;
1540                     
if ( valid ) {
1541                         submitted = validator.formSubmitted;
1542                         validator.resetInternals();
1543                         validator.toHide = validator.errorsFor( element );
1544                         validator.formSubmitted = submitted;
1545                         validator.successList.push( element );
1546                         validator.invalid[ element.name ] =
false;
1547                         validator.showErrors();
1548                     }
else {
1549                         errors = {};
1550                         message = response || validator.defaultMessage( element, { method: method, parameters:
value } );
1551                         errors[ element.name ] = previous.message = message;
1552                         validator.invalid[ element.name ] =
true;
1553                         validator.showErrors( errors );
1554                     }
1555                     previous.valid = valid;
1556                     validator.stopRequest( element, valid );
1557                 }
1558             }, param ) );
1559             
return "pending";
1560         }
1561     }
1562
1563 } );

1564
1565 // Ajax mode: abort
1566 // usage: $.ajax({ mode: "
abort"[, port: "uniqueport"]});
1567 //
if mode:"abort" is used, the previous request on that port (port can be undefined) is aborted via XMLHttpRequest.abort()
1568
1569 var
pendingRequests = {},
1570     ajax;

1571
1572 // Use a prefilter
if available (1.5+)
1573 if
( $.ajaxPrefilter ) {
1574     $.ajaxPrefilter( function( settings, _, xhr ) {
1575         
var port = settings.port;
1576         
if ( settings.mode === "abort" ) {
1577             
if ( pendingRequests[ port ] ) {
1578                 pendingRequests[ port ].abort();
1579             }
1580             pendingRequests[ port ] = xhr;
1581         }
1582     } );
1583 }
else {
1584
1585     
// Proxy ajax
1586     ajax = $.ajax;
1587     $.ajax = function( settings ) {
1588         
var mode = ( "mode" in settings ? settings : $.ajaxSettings ).mode,
1589             port = ( "
port" in settings ? settings : $.ajaxSettings ).port;
1590         
if ( mode === "abort" ) {
1591             
if ( pendingRequests[ port ] ) {
1592                 pendingRequests[ port ].abort();
1593             }
1594             pendingRequests[ port ] = ajax.apply(
this, arguments );
1595             
return pendingRequests[ port ];
1596         }
1597         
return ajax.apply( this, arguments );
1598     };
1599 }

1600 return
$;
1601 }));



Website quản lý người dùng và bán hàng theo mô hình Affiliate, chia lợi nhuận theo affiliate 20.566 lượt xem

Gõ tìm kiếm nhanh...